package com.googlecode.perfectable.visuable.visual.custom;

import java.util.List;

import com.google.common.base.Optional;
import com.googlecode.perfectable.eventable.routing.Source;
import com.googlecode.perfectable.prosperable.message.ClientMessage;
import com.googlecode.perfectable.visuable.message.client.ValueChangeMessageHandler;
import com.googlecode.perfectable.visuable.renderer.ElementRenderer;
import com.googlecode.perfectable.visuable.renderer.VisualRenderer;
import com.googlecode.perfectable.visuable.structure.Attribute;
import com.googlecode.perfectable.visuable.visual.IdentifiedVisuals;
import com.googlecode.perfectable.visuable.visual.MessageHandlingVisual;
import com.googlecode.perfectable.visuable.visual.ValueHoldingVisual;

public class InputVisual implements ValueHoldingVisual, MessageHandlingVisual {
	public static final String ELEMENT_NAME = "input";

	private static final String TYPE_ATTRIBUTE_NAME = "type";
	private static final String VALUE_ATTRIBUTE_NAME = "value";

	private static final String VALUE_WHEN_ATTRIBUTE_MISSING = "";

	private final ValueChangeMessageHandler handler = ValueChangeMessageHandler.create(this);

	private final String identifier;
	private final InputType type;

	private String value;

	public enum InputType {
		HIDDEN("hidden"),
		SUBMISSION("submit"),
		TEXTUAL("text"); // MARK MORE!

		public static final InputType DEFAULT = TEXTUAL;

		private String htmlType;

		private InputType(String htmlType) {
			this.htmlType = htmlType;
		}

		public static InputType fromHtmlType(String htmlType) {
			for(InputType candidate : values()) {
				if(candidate.htmlType.equals(htmlType)) {
					return candidate;
				}
			}
			throw new IllegalArgumentException("Input type '" + htmlType + "' is not supported");
		}

		public String htmlType() {
			return this.htmlType; // MARK render?
		}
	}

	public static InputVisual create(List<Attribute> elementAttributes) {
		String identifier = IdentifiedVisuals.extractIdentifier(elementAttributes);
		Optional<String> typeAttribute = Attribute.find(elementAttributes, TYPE_ATTRIBUTE_NAME);
		InputType type = InputType.DEFAULT;
		if(typeAttribute.isPresent()) {
			String htmlType = typeAttribute.get();
			type = InputType.fromHtmlType(htmlType);
		}
		Optional<String> valueAttribute = Attribute.find(elementAttributes, VALUE_ATTRIBUTE_NAME);
		String value = valueAttribute.or(VALUE_WHEN_ATTRIBUTE_MISSING);
		return new InputVisual(identifier, type, value);
	}

	public InputVisual(String identifier, InputType type, String value) {
		this.identifier = identifier;
		this.type = type;
		this.value = value;
	}

	@Override
	public String identifier() {
		return this.identifier;
	}

	@Override
	public void render(VisualRenderer painter) {
		try(ElementRenderer nestedPainter = painter.element(ELEMENT_NAME)) {
			IdentifiedVisuals.render(nestedPainter, this);
			nestedPainter.attribute(TYPE_ATTRIBUTE_NAME, this.type.htmlType());
			nestedPainter.attribute(VALUE_ATTRIBUTE_NAME, this.value);
		}
	}

	@Override
	public String value() {
		return this.value;
	}

	@Override
	public void setValue(String newValue) {
		this.value = newValue;
	}

	@Override
	public void registerMessageHandlers(Source<ClientMessage> source) {
		source.listen(this.handler);
	}

}
